package io.github.yfblock.frame.Core.Servlet;

import io.github.yfblock.frame.Core.Analyzer.UrlTreeNode;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class UrlPatternServlet extends AbstractServlet{
    protected UrlTreeNode rootUrlTreeNode = new UrlTreeNode();  // 根节点
    protected boolean isSpecificUpperLow = false;               // todo 后期添加: 是否识别大小写

    /**
     * 初始化过程过程
     * @throws ServletException
     */
    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
    }

    /**
     * 添加一个新的节点
     * @param url 节点的完整索引路径
     * @param method 节点方法
     * @param objectClass 节点对象
     */
    public void addNode(String url, Method method, Class<?> objectClass) {
        this.addNode(url, method, objectClass, rootUrlTreeNode);
    }

    /**
     * 添加一个新的节点到目标节点， 自动建立路径
     * @param url           节点相对路径
     * @param method        节点方法
     * @param objectClass   节点对象名称
     * @param targetNode    父节点
     */
    public void addNode(String url, Method method, Class<?> objectClass, UrlTreeNode targetNode) {
        url = url.trim();
        String[] nodeUrls = url.split("/");
        for(String nodeUrl:nodeUrls) {
            if(nodeUrl.equals("")) continue;        // 跳过空节点路径
            UrlTreeNode tempNode = getNodeFromChildren(nodeUrl, targetNode);
            if(tempNode==null) {
                tempNode = new UrlTreeNode();
                tempNode.setUrl(nodeUrl);
                addNodeToChildren(tempNode, targetNode);
            }
            targetNode = tempNode;
        }
        targetNode.setMethod(method);
        targetNode.setObjectBean(objectClass.getName());
    }

    /**
     * 使用nodeUrl从sourceNode中获取节点，无返回值则为null
     * @param nodeUrl 节点路径
     * @param sourceNode 源节点
     * @return 获取到的节点
     */
    private UrlTreeNode getNodeFromChildren(String nodeUrl, UrlTreeNode sourceNode) {
        nodeUrl = nodeUrl.trim();
        for(UrlTreeNode node:sourceNode.getChildren()) {
            if(node.getUrl().equals(nodeUrl)) {
                return node;
            }
        }
        return null;
    }

    /**
     * 添加节点到目标节点
     * @param urlTreeNode 要添加的节点
     * @param destinationNode 目标节点
     */
    private void addNodeToChildren(UrlTreeNode urlTreeNode, UrlTreeNode destinationNode) {
        destinationNode.getChildren().add(urlTreeNode);
    }

    /**
     * 根据完整路径获取节点
     * @param url 完整路径
     * @return 节点
     */
    public UrlTreeNode getNode(String url) {
        List<UrlTreeNode> allMatches = new ArrayList<>();
        UrlTreeNode tempNode = rootUrlTreeNode; // 精准匹配临时节点
        UrlTreeNode fuzzyNode = null;
        url = url.trim();
        String[] nodeUrls = url.split("/");
        for(String nodeUrl:nodeUrls) {
            if(nodeUrl.equals("")) continue;    // 跳过空节点

            fuzzyNode = getNodeFromChildren("*", tempNode); // 查询模糊节点
            if(fuzzyNode != null) allMatches.add(fuzzyNode);

            tempNode = getNodeFromChildren(nodeUrl, tempNode);

            if(tempNode==null) {    // 如果没有查询到结果 则返回模糊查询的最长的结果
                for(int i = allMatches.size() - 1; i >= 0;i--) {
                    if(allMatches.get(i).getMethod()!=null) return allMatches.get(i);
                }
                return null;
            }
        }
        return tempNode;
    }

    /**
     * 根据完整路径删除节点
     * @param url 完整路径
     */
    public void removeNode(String url) {
        UrlTreeNode parentNode = rootUrlTreeNode;   // 父节点
        UrlTreeNode tempNode = rootUrlTreeNode;     // 查询到的要删除得到节点

        // 查询过程
        url = url.trim();
        String[] nodeUrls = url.split("/");
        for(String nodeUrl:nodeUrls) {
            parentNode = tempNode;
            if(nodeUrl.equals("")) continue;    // 跳过空节点
            tempNode = getNodeFromChildren(nodeUrl, parentNode);
            if(tempNode==null) return;          // 如果要删除的节点不存在
        }
        // 查询完成 删除节点
        parentNode.getChildren().remove(tempNode);
    }

    /**
     * 输出树节点
     */
    public void printTreeNodes(UrlTreeNode rootUrlTreeNode, int tabBefore) {
        for(int i = 0;i < tabBefore;i++) {
            System.out.print("    ");
        }
        System.out.println(rootUrlTreeNode);
        for(UrlTreeNode node:rootUrlTreeNode.getChildren()) {
            printTreeNodes(node, tabBefore+1);
        }
    }
}
